#ifndef __SUBSYSTEM_WEATHER_H__
#define __SUBSYSTEM_WEATHER_H__

#include "Subsystem.hpp"
#include "Engine/Random.hpp"
#include "Engine/MathUtils.hpp"
#include <queue>

using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    class SubsystemBodies;
    class SubsystemTerrain;
    class SubsystemExplosions;
    class SubsystemTimeOfDay;
    class SubsystemGameInfo;
    class SubsystemTerrain;
    class SubsystemSnowBlockBehavior;
    class TerrainChunk;

    enum class PrecipitationType
    {
        Rain,
        Snow
    };
    struct PrecipitationShaftInfo
    {
        PrecipitationType Type;
        float Intensity;
        int32_t YLimit;
    };

    // 天气系统
    class SubsystemWeather : public Subsystem
    {
    public:
        void makeLightningStrike(const Vector3 &targetPosition);
        void netMakeLightningStrike(const Vector3 &targetPosition);
        void manualLightingStrike(const Vector3 &position, const Vector3 &direction);

        PrecipitationShaftInfo getPrecipitationShaftInfo(int32_t x, int32_t z);
        void freezeThawAndDepositSnow(TerrainChunk *chunk);


		static inline int32_t GetTemperatureAdjustmentAtHeight(int32_t y)
		{
			return (int32_t)MathUtils::Round((y > 64) ? (-0.0008f * MathUtils::Sqr(y - 64)) : (0.1f * (64 - y)));
		}
		static inline bool IsPlaceFrozen(int32_t temperature, int32_t y)
		{
			return temperature + GetTemperatureAdjustmentAtHeight(y) <= 0;
		}
        static inline bool ShaftHasSnowOnIce(int32_t x, int32_t z)
		{
			return MathUtils::Hash((uint32_t)((x & 0xFFFF) | (z << 16))) > 429496729;
		}

    public:
        SubsystemWeather();

        virtual void update(float dt) override;
        virtual void load(const nlohmann::json& json) override;
        virtual void save(nlohmann::json& json) override;
        virtual void saveToMsgJson(nlohmann::json &jsonData) override;

        virtual const std::string& getName() const override;
        virtual SubUpdateType getUpdateType() override;

    protected:
        float calculateLightIntensity(float timeOfDay);
        void updateLightAndViewParameters();

    protected:
        SubsystemTerrain *m_subsystemTerrain;
        SubsystemSnowBlockBehavior *m_subsystemSnowBlockBehavior;
        std::queue<Point2> m_waitHandleChunkQueue;

    public:
        SubsystemBodies *subsystemBodies;
        SubsystemTerrain *subsystemTerrain;
        SubsystemExplosions *subsystemExplosions;
        SubsystemTimeOfDay *timeOfDay;
        SubsystemGameInfo *gameInfo;

        int32_t moonPhase;
        int32_t skylightValue;
        float skylightIntensity;
        double weatherStartTime;
        double weatherEndTime;
        float lightningIntensity;
        float globalPrecipitationIntensity;
    };

    inline SubsystemWeather::SubsystemWeather() {}
}

#endif